﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 
// See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Actors.Languages;
using System.Threading.Actors.Utilities;
using System.Threading.Tasks;

namespace System.Threading.Actors
{
    /// <summary>
    /// For unit testing, StandaloneActor will let us easily simulate most actor method calling logic, avoiding networking
    /// issues or taking a dependency on the actor runtime.  Specifically, this will help with testing actor to actor method 
    /// calls via IActorProxy instances.
    /// </summary>
    public class StandaloneActor : IActor
    {
        private IActorState _state;
        private String _name;
        private ActorServiceHelper m_actorServiceHelper; // Some common logic for actor services

        public StandaloneActor(IActorState state, String actorName, String[] methodNames, Func<IActorState, Object[], Object>[] methods)
        {
            if (methodNames != null && methods != null && methodNames.Length != methods.Length)
                throw new ArgumentException("Number of actor method names must equal the number of actor methods");

            _state = state;
            _name = actorName;

            m_actorServiceHelper = new ActorServiceHelper(state, _name, actorState => {
                if (methodNames != null)
                    for (int i = 0; i < methodNames.Length; i++)
                        actorState.Set(methodNames[i], methods[i]);
            });

            StandaloneActorState sas = state as StandaloneActorState;
            if (sas != null)
                sas.AddExistingActor(_name, this, sas);
        }

        public Task<string> CallMethod(string clientId, int clientSequenceNumber, string partitionName, string methodName, string[] parameters)
        {
            return m_actorServiceHelper.CallMethod(clientId, clientSequenceNumber, methodName, parameters);
        }

        public Task<string> AddAssembly(int clientSequenceNumber, string partitionName, string assemblyName, byte[] assemblyBytes)
        {
            return m_actorServiceHelper.AddAssembly(clientSequenceNumber, assemblyName, assemblyBytes);
        }

        public string Subscribe(int clientSequenceNumber, string partitionName, string eventType, IPublicationCallbackContract context)
        {
            _state.Subscribe(context, eventType);

            return SerializationHelper.Serialize(ActorServiceResult.FromResult(clientSequenceNumber, true));
        }

        public string Unsubscribe(int clientSequenceNumber, string partitionName, string eventType, IPublicationCallbackContract context)
        {
            _state.Unsubscribe(context, eventType);

            return SerializationHelper.Serialize(ActorServiceResult.FromResult(clientSequenceNumber, true));
        }

        public string UnsubscribeAll(int clientSequenceNumber, string partitionName, IPublicationCallbackContract context)
        {
            _state.UnsubscribeAll(context);

            return SerializationHelper.Serialize(ActorServiceResult.FromResult(clientSequenceNumber, true));
        }

        public string Ping(int clientSequenceNumber, string partitionName)
        {
            var myAddress = _name;
            return SerializationHelper.Serialize(ActorServiceResult.FromResult(clientSequenceNumber, myAddress));
        }

        public Task<string> AddMethod(int clientSequenceNumber, string partitionName, int language, string methodName, string methodImpl)
        {
            return m_actorServiceHelper.AddMethod(clientSequenceNumber, (SupportedLanguages)language, methodName, methodImpl);
        }

        public string Configure(int clientSequenceNumber, string partitionName, string configurationString)
        {
            return m_actorServiceHelper.Configure(clientSequenceNumber, configurationString);
        }

        public string DeleteSelf(int clientSequenceNumber, string partitionName)
        {
            return m_actorServiceHelper.DeleteSelf(clientSequenceNumber);
        }
    }
}
